using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using StaffWarsFm.Lib.Data;
using StaffWarsFm.Services;
using System.Diagnostics;

namespace StaffWarsFm.Server
{
    public class RadioService : IRadioService
    {
        private static List<ClientReference> clients = new List<ClientReference>();
        private static IRadioServiceClient speakerMasterClient;
        private static ClientReference radioMasterRef;
        private static Challenge currentChallenge;

        public void GutenTag(User user)
        {
            var client = GetClient();
            var clientRef = new ClientReference {Client = client, User = user};

            clients.Add(clientRef);

            // Assume the first connected client is the speaker master
            if (speakerMasterClient == null)
                speakerMasterClient = client;

            // Assume the first connected client also starts as the radio master
            if (radioMasterRef == null)
                radioMasterRef = clientRef;

            client.SetCurrentRadioMaster(radioMasterRef.User);
        }

        public void AufWiedersehen()
        {
            var client = GetClient();

            var clientRef = clients.Single(cr => cr.Client == client);
            clients.Remove(clientRef);
        }

        public void Challenge(User challengingUser)
        {
            var challengingClient = GetClient();

            if (currentChallenge != null)
                challengingClient.ChallengeResponse(false);

            var clientRef = clients.Single(cr => cr.Client == challengingClient);
            currentChallenge = new Challenge(clientRef, radioMasterRef, clients.Select(cr => cr.User));

            radioMasterRef.Client.ChallengeRequest(challengingUser);
            challengingClient.ChallengeResponse(true);
        }

        public void DeclineChallenge()
        {
            SetRadioMaster(currentChallenge.Challenger);
            FinishChallenge();
        }

        public void AcceptChallenge()
        {
            if (currentChallenge.Question != null)
            {
                AskQuestion(currentChallenge.Question);
            }
            else
            {
                StartAskQuestion();
            }
        }

        private void StartAskQuestion()
        {
            radioMasterRef.Client.GeneratingQuestion();
            currentChallenge.Challenger.Client.GeneratingQuestion();

            currentChallenge.QuestionGenerated += currentChallenge_QuestionGenerated;
        }

        public void SubmitAnswer(bool wasCorrect)
        {
            var client = GetClient();
            var clientRef = clients.Single(cr => cr.Client == client);

            var result = currentChallenge.SubmitAnswer(clientRef, wasCorrect);

            if (result.Complete)
            {
                if (result.Winner != null)
                {
                    currentChallenge = null;
                    SetRadioMaster(result.Winner);
                    return;
                }

                // Generate another question
                currentChallenge.StartQuestionGeneration();
                StartAskQuestion();
            }
        }

        private void AskQuestion(Question question)
        {
            Debug.WriteLine("Asking Question");
            radioMasterRef.Client.AskQuestion(question);
            currentChallenge.Challenger.Client.AskQuestion(question);
        }

        private void currentChallenge_QuestionGenerated(object sender, EventArgs e)
        {
            var question = currentChallenge.Question;

            AskQuestion(question);

            currentChallenge.QuestionGenerated -= currentChallenge_QuestionGenerated;
        }

        private void SetRadioMaster(ClientReference clientReference)
        {
            radioMasterRef = clientReference;
            Broadcast(c => c.SetCurrentRadioMaster(clientReference.User));
        }

        private void FinishChallenge()
        {
            currentChallenge = null;
        }

        private static IRadioServiceClient GetClient()
        {
            return OperationContext.Current.GetCallbackChannel<IRadioServiceClient>();
        }

        private void Broadcast(Action<IRadioServiceClient> clientAction)
        {
            foreach (var client in clients)
                clientAction(client.Client);
        }
    }
}